[iOS 8] Swiftでデザインパターン No.10 Builder
Builder
Builder とは
英単語 Build には以下のような意味があります。
- 組み立てる
- 建築する
Builder パターンは、オブジェクトの生成過程を抽象化することによって、動的なオブジェクトの生成を可能にするパターンです。
クラス図
ポイント
- 抽象クラス Builder の buildPart オペレーションはデフォルトでは何も行わない
- 各 ConcreteBuilder クラスが、生成する構成要素に対するオペレーションのみをオーバーライドする
サンプルコード
今回は「勇者」オブジェクトを生成し、以下の項目を設定するプログラムを考えてみました。
- レベル
- ぶき
- よろい
Builder
class Builder: NSObject { func buildLevel(level: Int) {} func buildSword(sword: String) {} func buildArmor(armor: String) {} }
こちらは Builder クラスです。 「レベル」、「ぶき」、「よろい」を設定するメソッドを持っています。
HeroBuilder
class HeroBuilder: Builder { let hero = Hero() override func buildLevel(level: Int) { self.hero.level = level } override func buildSword(sword: String) { self.hero.sword = sword } override func buildArmor(armor: String) { self.hero.armor = armor } func getResult() -> Hero { return self.hero } }
こちらは ConcreteBuilder クラスです。 「勇者」オブジェクトを構築するクラスです。
Hero
class Hero: NSObject { var level: Int? var sword: String? var armor: String? func showStatus() { println("### Status ###") println("Level: (self.level)") println("Sword: (self.sword)") println("Armor: (self.armor)") println("##############") } func checkStatus() { if let level = self.level, sword = self.sword, armor = self.armor where level > 10 { println("そなたは もう じゅうぶんにつよい!") } else { println("レベルが あがったら また くるがいい") println("ぶきや ぼうぐは そうびしないと いみがないぞ") } } }
こちらは Product クラスです。 「勇者」を表します。 ステータスを表示するメソッド、ステータスをチェックするメソッドを持ちます。
Director
class Director: NSObject { let builder: Builder init(builder: Builder) { self.builder = builder } func construct() { self.builder.buildLevel(30) self.builder.buildSword("おうじゃのけん") self.builder.buildArmor("ひかりのよろい") } }
こちらは Director クラスです。 Builder クラスのインタフェースを使って「勇者」を生成します。
実行
let heroBuilder = HeroBuilder() let director = Director(builder: heroBuilder) director.construct() let hero = heroBuilder.getResult() hero.showStatus() hero.checkStatus()
実行結果
### Status ### Level: Optional(30) Sword: Optional("おうじゃのけん") Armor: Optional("ひかりのよろい") ############## そなたは もう じゅうぶんにつよい!
オブジェクトを一度に作成するパターンとは違い、Builder パターンでは Product オブジェクトを段階的に作成します。 これにより Product オブジェクトの内部構造を、より細かくコントロールすることができるようになります。
余裕があれば、装備に「たて」や「かぶと」、キャラクターに「戦士」や「魔法使い」が追加された時についても考えてみましょう。
Multiple Optional Bindings
Hero クラスに無理やり作成した以下のメソッドに注目してください。
func checkStatus() { if let level = self.level, sword = self.sword, armor = self.armor where level > 10 { println("そなたは もう じゅうぶんにつよい!") } else { println("レベルが あがったら また くるがいい") println("ぶきや ぼうぐは そうびしないと いみがないぞ") } }
ここでは Optional Bindings を使用していますが、Swift 1.2 からは複数の変数について一行の if 文で書けるようになりました。 ネストが深くなることがなくなるので、これは嬉しい進化ですね。(右に長くなってはしまいますが・・・)
まとめ
- Swift 1.2 からは複数の Optional Bindings に対応した!
- バインドした変数について条件式も同時に書ける!